<html>
<head>
<title>jqlisp.html - jslisp was taken</title>
<script src="jquery-1.4.2.js"></script>
<link rel="stylesheet" href="qunit.css" type="text/css" media="screen" />
<script src="qunit.js"></script>
<script src="jquery.json-2.2.js"></script>
<script>

$(document).ready(function() {
    $('#evaluate').click(function() {
        $('#output').val(LISP.evaluate($('#input').val()));
        alert(LISP.debugString);
    });
    LISP.doTests();
});
var LISP = {
    inlin : "",
    debug : true,
    debugString: '',
    Alist : [],
    evaluate : function(e) {
        return e
    },
    doDebug : function(s) {
        // alert(s);
        LISP.debugString += s;
    },
    isSymbol : function(x) { return typeof x == typeof ''; },
    isNumber : function(x) { return typeof x == typeof 0.0; },
    putSexp : function(s) { 
    // return string form of an S expression
        if (typeof s == typeof []) {
            if (false && s.length > 0 && s[0] == 'quote') return "'" + this.putSexp(s.slice(1));
            // else return '(' + this.map(function(x){return LISP.putSexp(x);},s).join(' ') + ')';
            else return '(' + s.map(LISP.putSexp).join(' ') + ')';
        }
        else return s;
    },
    getSexp : function() {
    // return and discard the next S expression, along with any nested ones in input
    },
    getToken : function() {
    // return and discard the next symbol, number or special character in input
    },
    nextCharOld : function() {
    // return (but don't discard) the next character in the input stream
    //   get more from the user if needed
    },
    nextChar : function() {
    // return (but don't discard) the next character in the input stream
    //   get more from the user if needed
    },
    getChar : function() {
    // return and discard the next character in the input stream
    },
    pairlis : function(x,y,alist) {
    // push symbols in x along with respective values in y onto the alist
        if (x.length==0) return alist;
        else return [[x[0],y[0]]].concat(this.pairlis(x.slice(1),y.slice(1),alist));
    },
    assoc : function(x,alist) {
    // look up x on the alist and return its value
        if (!alist) throw("Lisp error");
        else if (alist[0][0]==x) return alist[0][1];
        else return this.assoc(x,alist.slice(1));
    },
    apply_ : function(fn,args,alist) {
    // apply a function fn to its arguments in args
        if (this.debug) LISP.doDebug('--Apply--' + this.putSexp(fn) + ' Args=' + this.putSexp(args) + ' alist=' + this.putSexp(alist) + "\n");
        if (this.isSymbol(fn)) {
            if      (fn == 'atom') return typeof args[0] == typeof [] ? [] : 't';
            else if (fn == 'car') return args[0][0];     // first element of first arg
            else if (fn == 'cdr') return args.slice(1);  // tail of first arg
            else if (fn == 'eq')  return args[0] == args[1] ? 't' : [];
            else if (fn == 'not') return typeof args[0] == typeof [] && args[0].length == 0 ? 't' :  [];
            else if (fn == 'cons') {
                if (typeof args[1] != typeof []) args[1] = [args[1]];
                return [args[0]].concat(args[1]);
            }
        }
    },
    eval_ : function(exp_,alist) {
    // evaluate an S expression using the alist
        if (this.debug) LISP.doDebug( '--Eval---' + this.putSexp(exp_) + ' alist=' + this.putSexp(alist) + "\n");
        if      (exp_ == 't') return 't';
        else if (exp_ == 'nil') return [];
        else if (exp_ == 'alist') return LISP.Alist;
        else if (this.isNumber(exp_)) return exp_;
        else if (this.isSymbol(exp_)) return this.assoc(exp_,alist);
        else {
            if (exp_[0] == 'quote') return exp_[1];
        }
    },
    evcon : function(c,alist) {
    // evaluate cond. Note just the pairs passed in c
    },
    evlis : function(l,alist) {
    },
    doTests : function() {
        test('putSexp', function() {
            ok( LISP.putSexp('foo')=='foo' );
            ok( LISP.putSexp(['foo'])=='(foo)' );
            ok( LISP.putSexp(['quote', 'foo'])=="(quote foo)" );
            ok( LISP.putSexp(['a', ['b', 'c'], 'd'])=='(a (b c) d)' );
        });
        test('pairlis', function() {
            same( LISP.pairlis(['x'],['y'],[]),[['x','y']] );
            same( LISP.pairlis(['x'],['y'],[['a','b']]),[['x','y'],['a','b']] );
        });
        test('assoc', function() {
            ok( LISP.assoc('x',[['x','y']])=='y');
            ok( LISP.assoc('x',[['foo','bar'],['x','y']])=='y');
        });
        test('apply_', function() {
            ok(   LISP.apply_('atom',['foo'],          [])=='t');
            same( LISP.apply_('atom',[[]],             []),[]);
            ok(   LISP.apply_('car', [['foo']],        [])=='foo');
            same( LISP.apply_('cdr', [['foo']],        []),[]);
            ok(   LISP.apply_('eq',  ['foo','foo'],    [])=='t');
            same( LISP.apply_('eq',  ['foo','bar'],    []),[]);
            ok(   LISP.apply_('not', [[]],             [])=='t');
            same( LISP.apply_('not', ['foo'],          []),[]);
            same( LISP.apply_('cons',['foo',[]],       []),['foo']);
            same( LISP.apply_('cons',['foo',['bar']],  []),['foo','bar']);
            same( LISP.apply_('cons',[['foo'],['bar']],[]),[['foo'],'bar']);
        });
        test('eval_', function() {
            ok(   LISP.eval_('t',[])=='t');
            same( LISP.eval_('nil',[]),[]);
            ok(   LISP.eval_(1,[])==1);
            ok(   LISP.eval_('foo',[['foo','bar']])=='bar');
            ok(   LISP.eval_(['quote','foo'],[])=='foo');

        });
        test('single test', function() {
        });
    }
}

</script>
</head>
<body>
<h1>jqlisp</h1>
<textarea id="input">
(cdr '(a b c))
</textarea><br />
<input type="button" id="evaluate" value="eval"><br />
<textarea id="output">
</textarea>
<p>There are plenty of Javascript lisps out there, but none that I've seen demontrate the essense of the implementation
like Paul Graham's <a href="http://www.paulgraham.com/rootsoflisp.html">Roots of Lisp</a> <a href="http://lib.store.yahoo.net/lib/paulgraham/jmc.lisp">implementation</a> in Common Lisp or Chris Meyers' <a href="http://openbookproject.net//py4fun/lisp/lisp.html">Lisp in Python</a>.</p>
<h1 id="qunit-header">jqlisp unit tests</h1>
<h2 id="qunit-banner"></h2>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
</body>
</html>

